/*************************************************************
   Copyright(C) 2017 by WuIslet
   All rights reserved.
   
   FindInPrefab.cs
   UnityFramework
   
   Created by WuIslet on 2018-02-01.
   
*************************************************************/
#define USE_EDITOR_UI_CONTROLDATA
#if !USE_ILRUNTIME

using System.Collections.Generic;
using System.Reflection;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using Object = UnityEngine.Object;

public partial class FindInPrefab
{
    // 2. 命中判断 HitRuleClass
    private enum HitRule
    {
        None,
        名字含有,
        tag等于,
        含有Component,
        Component为空,
        含有指定图片资源, //TODO 改成含有任意资源。
        图片资源为空,
        含有指定路径下的某个图片资源,
        资源无人引用,
    }
    private static HitRule mHitRule;
    private static Dictionary<HitRule, Phase<FindResult, bool>> HitRuleClass;
    private static void ResetHitRule()
    {
        HitRuleClass = new Dictionary<HitRule, Phase<FindResult, bool>>
        {
            {HitRule.None, new HitWithNone()},
            {HitRule.名字含有, new HitWithName()},
            {HitRule.tag等于, new HitWithTag()},
            {HitRule.含有Component, new HitWithComponent()},
            {HitRule.Component为空, new HitWithNullComponent()},
            {HitRule.含有指定图片资源, new HitWithTexture()},
            {HitRule.图片资源为空, new HitWithNullTexture()},
            {HitRule.含有指定路径下的某个图片资源, new HitWithTexturePath()},
            {HitRule.资源无人引用, new HitWithNoUsage()},
        };
    }

    #region class None
    class HitWithNone : Phase<FindResult, bool>
    {
    }
    #endregion class None

    #region class 名字含有
    class HitWithName : Phase<FindResult, bool>
    {
        private string[] example = new[] { "效果图", "BGBlur" };
        private string keyword;
        override public bool FuncReturn(FindResult input)
        {
            if (string.IsNullOrEmpty(keyword))
                return true;

            return input.name.Contains(keyword);
        }

        override public void OnDraw()
        {
            keyword = EditorGUILayout.TextField("    关键字：", keyword);
            EditorGUILayout.BeginHorizontal();
            foreach (var key in example)
            {
                if (GUILayout.Button(key, GUILayout.MaxWidth(100)))
                {
                    keyword = key;
                }
            }
            EditorGUILayout.EndHorizontal();
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (string.IsNullOrEmpty(keyword))
            {
                return "请输入关键字";
            }
            return "";
        }
    }
    #endregion class 名字含有

    #region class tag等于
    class HitWithTag : Phase<FindResult, bool>
    {
        private string[] example = new[] {"EditorOnly", "UI_ControlData"};
        private string keyword;
        override public bool FuncReturn(FindResult input)
        {
            if (string.IsNullOrEmpty(keyword))
                return true;

            return input.go.CompareTag(keyword);
        }

        override public void OnDraw()
        {
            keyword = EditorGUILayout.TextField("    关键字：", keyword);
            EditorGUILayout.BeginHorizontal();
            foreach (var key in example)
            {
                if (GUILayout.Button(key, GUILayout.MaxWidth(100)))
                {
                    keyword = key;
                }
            }
            EditorGUILayout.EndHorizontal();
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (string.IsNullOrEmpty(keyword))
            {
                return "请输入关键字";
            }
            return "";
        }
    }
    #endregion class tag等于

    #region class 含有控件
    class HitWithComponent : Phase<FindResult, bool>
    {
        private bool findWithString = true;
        private bool fast = true;
        private string[] example = new[] { "Graphic", "Selectable", "Text", "TextMeshProUGUI", "Animator", "Button" };
        private string component = "Image";
        private MonoScript scriptObj;
        override public bool FuncReturn(FindResult input)
        {
            if (fast)
            {
                if (findWithString)
                {
                    if (string.IsNullOrEmpty(component))
                        return true;

                    return input.go.GetComponent(component) != null;
                }
                else
                {
                    if (scriptObj == null)
                        return true;
                    return input.go.GetComponent(scriptObj.GetClass()) != null;
                }
            }
            else
            {
                string find = "";
                if (findWithString)
                {
                    if (!string.IsNullOrEmpty(component))
                        find = component;
                }
                else
                {
                    if (scriptObj != null)
                        find = scriptObj.GetClass().Name;
                }

                var list = input.go.GetComponents<Component>();
                input.extraObjs = new List<UnityEngine.Object>(list.Length);
                for (int i = 0; i < list.Length; ++i)
                {
                    if (list[i] == null)
                        continue;
                    
                    if (string.IsNullOrEmpty(find) || list[i].GetType().Name == find)
                    {
                        input.extraObjs.Add(list[i]);
                    }
                }

                return input.extraObjs.Count > 0;
            }
        }

        override public void OnDraw()
        {
            fast = GUILayout.Toggle(fast, "快速查找？传递extraObjs");
            findWithString = GUILayout.Toggle(findWithString, "使用名字查找？");
            if (findWithString)
            {
                component = EditorGUILayout.TextField("    控件名：", component);
                EditorGUILayout.BeginHorizontal();
                foreach (var key in example)
                {
                    if (GUILayout.Button(key, GUILayout.MaxWidth(100)))
                    {
                        component = key;
                    }
                }
                EditorGUILayout.EndHorizontal();
            }
            else
            {
                scriptObj = (MonoScript)EditorGUILayout.ObjectField(scriptObj, typeof(MonoScript), true);
            }
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (findWithString && string.IsNullOrEmpty(component))
            {
                return "请输入控件名";
            }
            if (!findWithString && scriptObj == null)
            {
                return "请输入控件";
            }
            return "";
        }
    }
    #endregion class 含有控件

    #region class 控件为空
    class HitWithNullComponent : Phase<FindResult, bool>
    {
        override public bool FuncReturn(FindResult input)
        {
            var list = input.go.GetComponents<Component>();
            for (int i = 0, len = list.Length; i < len; ++i)
            {
                var component = list[i];
                if (component == null)
                    return true;
            }

            return false;
        }
    }
    #endregion class 控件为空

    #region class 含有指定图片资源
    class HitWithTexture : Phase<FindResult, bool>
    {
        private bool isSel = false;
        string mFindPath = ROOT_PATH;
        private Object mTarget;
        private string mTargetGUID;
        private bool isSprite;
        private ulong mTargetFileID;
        private string mTargetSerializeFileID;

        override public bool FuncReturn(FindResult input)
        {
            return NormalSearch(input);
        }

        private bool NormalSearch(FindResult input)
        {
            if (mTarget == null)
                return false;

            if (isSprite)
            {
                var image = input.go.GetComponent<Image>();
                if (image != null)
                {
                    return isTextureEqual(image.sprite);
                }
            }

            var graphic = input.go.GetComponent<Graphic>();
            if (graphic != null)
            {
                return isTextureEqual(graphic.mainTexture);
            }

            var selectable = input.go.GetComponent<Selectable>();
            if (selectable != null)
            {
                if (isTextureEqual(selectable.spriteState.highlightedSprite))
                    return true;
                if (isTextureEqual(selectable.spriteState.pressedSprite))
                    return true;
                if (isTextureEqual(selectable.spriteState.disabledSprite))
                    return true;
                if (isTextureEqual(selectable.spriteState.selectedSprite))
                    return true;
            }
            return false;
        }

        private bool isTextureEqual(Object target)
        {
            if (mTargetGUID == AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(target)))
            {
                if (isSprite)
                {
                    var goid = UnityEditor.GlobalObjectId.GetGlobalObjectIdSlow(target);
                    var fileID = goid.targetObjectId;
                    return (fileID == mTargetFileID);
                }
                else
                {
                    return true;
                }
            }
            else
            {
                return false;
            }
        }

        override public void OnDraw()
        {
            isSel = GUILayout.Toggle(isSel, "使用选中", GUILayout.MaxWidth(100));
            if (isSel)
            {
                mTarget = Selection.activeObject;
            }
            else
            {
                mTarget = EditorGUILayout.ObjectField(mTarget, typeof(Object), false);
            }

            EditorToolsUtils.DrawObjectDetail(mTarget, window);
            var selectedAssetPath = AssetDatabase.GetAssetPath(mTarget);
            mTargetGUID = AssetDatabase.AssetPathToGUID(selectedAssetPath);
            isSprite = (mTarget as Sprite) != null;
            if (isSprite)
            {
                var goid = UnityEditor.GlobalObjectId.GetGlobalObjectIdSlow(mTarget);
                mTargetFileID = goid.targetObjectId;
            }
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (isSave)
            {
                return "不需要需要启用保存prefab功能";
            }

            if (mTarget == null)
            {
                return "请输入待查找的资源";
            }

            if (((mTarget as Sprite) == null) && ((mTarget as Texture) == null))
            {
                return "选中对象的类型不正确";
            }
            return "";
        }
    }
    #endregion class 含有指定图片资源

    #region class 图片资源为空
    class HitWithNullTexture : Phase<FindResult, bool>
    {
        override public bool FuncReturn(FindResult input)
        {
            var subtmp = input.go.GetComponent<TMP_SubMeshUI>();
            if (subtmp != null) //提前过滤
                return false;

            var image = input.go.GetComponent<Image>();
            if (image != null)
            {
                if (image.sprite == null)
                {
                    return true;
                }
            }

            var graphic = input.go.GetComponent<Graphic>();
            if (graphic != null)
            {
                if (graphic.mainTexture == null)
                {
                    return true;
                }

            }
            return false;
        }
    }
    #endregion class 图片资源为空

    #region class 含有指定路径下的某个图片资源
    class HitWithTexturePath : Phase<FindResult, bool> //TODO 把资源的路径判断放到后处理，这里值摘取所有资源
    {
        bool mIsReverse = false;
        string mFindPath = ROOT_PATH;
        override public bool FuncReturn(FindResult input)
        {
            if (input.type == "UISkinSpriteData") //找UISkinSpriteData
            {
                var spriteData = input.rawObj as HMI.UI.Skins.Data.UISkinSpriteData;
                if (spriteData != null)
                {
                    var graphic = spriteData.sprite;
                    if (graphic != null)
                    {
                        var graphicPath = EditorToolsUtils.FormatValidPathName(AssetDatabase.GetAssetPath(graphic));
                        if (!graphicPath.EndsWith(".ttf") && (mIsReverse ^ graphicPath.StartsWith(mFindPath)))
                        {
                            input.extra = graphicPath;
                            return true;
                        }
                    }
                }
            }
            else if (input.type == "spriteatlas")
            {
                bool flag = false;
                var spriteData = input.rawObj as UnityEngine.U2D.SpriteAtlas;
                string[] dependencies = AssetDatabase.GetDependencies(AssetDatabase.GetAssetPath(spriteData));

                foreach (string dependency in dependencies)
                {                    
                    Object asset = AssetDatabase.LoadMainAssetAtPath(dependency);
                    Debug.LogWarning($"{mFindPath}<extra:{dependency}");
                    if (asset is Texture2D || asset is Sprite)
                    {
                        if (asset is Texture2D texture)
                        {
                            Object[] subAssets = AssetDatabase.LoadAllAssetsAtPath(dependency);
                            foreach (Object subAsset in subAssets)
                            {
                                if(!dependency.EndsWith(".ttf") && (mIsReverse ^ EditorToolsUtils.FormatValidPathName(dependency).StartsWith(mFindPath)))
                                {
                                    input.extra += dependency + "\n";
                                    flag = true;
                                    break;
                                }
                            }
                        }
                    }
                }
                return flag;
            }
            else //找Prefab
            {
                var graphic = input.go.GetComponent<Graphic>();
                if (graphic != null && graphic.mainTexture != null)
                {
                    var graphicPath = EditorToolsUtils.FormatValidPathName(AssetDatabase.GetAssetPath(graphic.mainTexture));
                    if (!graphicPath.EndsWith(".ttf") && (mIsReverse ^ graphicPath.StartsWith(mFindPath)))
                    {
                        input.extra = graphicPath;
                        return true;
                    }
                }

                var selectable = input.go.GetComponent<Selectable>();
                if (selectable != null)
                {
                    if (selectable.spriteState.selectedSprite != null)
                    {
                        var graphicPath = EditorToolsUtils.FormatValidPathName(AssetDatabase.GetAssetPath(selectable.spriteState.selectedSprite));
                        if (!graphicPath.EndsWith(".ttf") && (mIsReverse ^ graphicPath.StartsWith(mFindPath)))
                        {
                            input.extra = graphicPath;
                            return true;
                        }
                    }
                    if (selectable.spriteState.highlightedSprite != null)
                    {
                        var graphicPath = EditorToolsUtils.FormatValidPathName(AssetDatabase.GetAssetPath(selectable.spriteState.highlightedSprite));
                        if (!graphicPath.EndsWith(".ttf") && (mIsReverse ^ graphicPath.StartsWith(mFindPath)))
                        {
                            input.extra = graphicPath;
                            return true;
                        }
                    }
                    if (selectable.spriteState.pressedSprite != null)
                    {
                        var graphicPath = EditorToolsUtils.FormatValidPathName(AssetDatabase.GetAssetPath(selectable.spriteState.pressedSprite));
                        if (!graphicPath.EndsWith(".ttf") && (mIsReverse ^ graphicPath.StartsWith(mFindPath)))
                        {
                            input.extra = graphicPath;
                            return true;
                        }
                    }
                    if (selectable.spriteState.disabledSprite != null)
                    {
                        var graphicPath = EditorToolsUtils.FormatValidPathName(AssetDatabase.GetAssetPath(selectable.spriteState.disabledSprite));
                        if (!graphicPath.EndsWith(".ttf") && (mIsReverse ^ graphicPath.StartsWith(mFindPath)))
                        {
                            input.extra = graphicPath;
                            return true;
                        }
                    }
                }
            }

            return false;
        }

        override public void OnDraw()
        {
            mIsReverse = EditorGUILayout.Toggle("反向查找", mIsReverse);
            mFindPath = EditorToolsUtils.DrawDragBrowserFolderPath("    文件夹：", mFindPath, "", "");
        }

        override public string CheckNeed(bool isSave, SearchRange sr, bool isDS, HitRule hr, AfterDeal ad)
        {
            if (string.IsNullOrEmpty(mFindPath))
            {
                return "请输入文件夹路径";
            }
            return "";
        }
    }
    #endregion class 含有指定路径下的某个图片资源

    #region class 资源无人引用
    class HitWithNoUsage : Phase<FindResult, bool>
    {
        override public bool FuncReturn(FindResult input)
        {
            var keyword = EditorToolsUtils.DrawObjectDetail(input.rawObj, window);
            var result = SearchWithRG(keyword, false, false);
            if (result == null || result.Count <= 0)
            {
                return true;
            }
            return false;
        }
    }
    #endregion class 资源无人引用

    private bool DrawHitRule()
    {
        bool isOK = true;
        EditorGUILayout.BeginVertical("Box");
        mHitRule = (HitRule)EditorGUILayout.EnumPopup("命中判断：", mHitRule, GUILayout.MinWidth(100));
        if (HitRuleClass != null && HitRuleClass.ContainsKey(mHitRule))
        {
            var cls = HitRuleClass[mHitRule];
            var warning = cls.CheckNeed(mIsSavePrefab, mSearchRange, mIsDeepSearch, mHitRule, mAfterDeal);
            if (!string.IsNullOrEmpty(warning))
            {
                isOK = false;
                EditorGUILayout.HelpBox(warning, MessageType.Error);
            }
            cls.OnDraw();
        }
        EditorGUILayout.EndVertical();
        return isOK;
    }
}
#endif